﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JBeamLibrary.VehicleParts.Elements;
using JBeamLibrary.VehicleParts.Enums;

namespace JBeamLibrary.VehicleParts.Collections
{
    public class GearCollection : KeyedCollection<GearPosition, Gear>
    {
        #region Fields

        public event EventHandler<Gear> GearAdded;
        public event EventHandler GearRemoved;

        #endregion

        #region CTORs

        /// <summary>Creates a new gear collection</summary>
        public GearCollection()
        {

        }

        /// <summary>Creates a new gear collection</summary>
        /// <param name="gears"></param>
        public GearCollection(IEnumerable<Gear> gears)
        {
            AddRange(gears);
        }

        #endregion

        #region Methods

        /// <summary>Adds a new gear</summary>
        /// <param name="value"></param>
        public void Append(float value)
        {
            Add((GearPosition)(Count - 1), value);
        }

        /// <summary>Adds a gear</summary>
        /// <param name="gear"></param>
        public new void Add(Gear gear)
        {
            base.Add(gear);

            if (GearAdded != null)
                GearAdded(this, gear);
        }

        /// <summary>Creates a gear and adds it to the list</summary>
        /// <param name="position"></param>
        /// <param name="value"></param>
        public void Add(GearPosition position, float value)
        {
            Add(new Gear(position, value));
        }

        /// <summary>Adds a collection of gears to the list</summary>
        /// <param name="gears"></param>
        public void AddRange(IEnumerable<Gear> gears)
        {
            foreach (var gear in gears)
                Add(gear);
        }

        /// <summary>Updates or adds the gear with a matching position in the list</summary>
        /// <param name="position"></param>
        /// <param name="value"></param>
        public void UpdateAdd(GearPosition position, float value)
        {
            UpdateAdd(new Gear(position, value));
        }

        /// <summary>Updates or adds the gear with a matching position in the list</summary>
        /// <param name="gear"></param>
        public void UpdateAdd(Gear gear)
        {
            if (Contains(gear.Position))
                Remove(gear.Position);
            Add(gear);
        }

        /// <summary>Updates or adds gears of a given collection to the list</summary>
        /// <param name="gears"></param>
        public void UpdateAddRange(IEnumerable<Gear> gears)
        {
            foreach (var gear in gears)
                UpdateAdd(gear);
        }

        /// <summary>Removes a gear</summary>
        /// <param name="gear"></param>
        public new void Remove(Gear gear)
        {
            base.Remove(gear);

            ReorderItems();

            if (GearRemoved != null)
                GearRemoved(this, new EventArgs());
        }

        /// <summary>Removes the gear at the specified index</summary>
        /// <param name="index"></param>
        public new void RemoveAt(int index)
        {
            base.RemoveAt(index);

            ReorderItems();

            if (GearRemoved != null)
                GearRemoved(this, new EventArgs());
        }

        /// <summary>Removes the last gear</summary>
        public void RemoveTail()
        {
            RemoveAt(Count - 1);
        }

        /// <summary>Returns a new gear</summary>
        /// <returns></returns>
        public Gear GetNew()
        {
            return new Gear((GearPosition)(Count - 1), 0f);
        }

        /// <summary>Reorders the items changing their keys if needed</summary>
        public void ReorderItems()
        {
            for (var i = 0; i < Count; i++)
            {
                var item = this[i];
                var cPos = i - 1;
                var rPos = (int)item.Position;
                if (cPos != rPos)
                {
                    item.Position = (GearPosition)cPos;
                }
            }
        }

        #endregion

        #region KeyedCollection

        protected override GearPosition GetKeyForItem(Gear item)
        {
            return item.Position;
        }

        #endregion
    }
}
